﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.IO;

namespace FileListMaker
{
    public partial class ComboBox2 : UserControl, IControlConfigurationTarget
    {
        public IList DataSource
        {
            get { return (IList)comboBox1.DataSource; }
            set { comboBox1.DataSource = value; }
        }

        public string DisplayMember
        {
            get { return comboBox1.DisplayMember; }
            set { comboBox1.DisplayMember = value; }
        }

        public string ValueMember
        {
            get { return comboBox1.ValueMember; }
            set { comboBox1.ValueMember = value; }
        }

        public ComboBox2()
        {
            InitializeComponent();
        }

        public string Id { get; private set; }

        public void LoadConfiguration(string id)
        {
            this.Id = id;
            DataSource = new ComboBox2DataSource(this);
            ControlConfiguration.Current.Add(this);  //DataSourceが生成されている必要あり。
        }

        public override string Text
        {
            get
            {
                return comboBox1.Text;
            }
            set
            {
                comboBox1.Text = value;
            }
        }

        public void InsertHistory(string value)
        {
            DataSource.Add(value);
        }

        private IConfigReaderWriter configRW = null;
        public IConfigReaderWriter ConfigReaderWriter
        {
            get
            {
                if (configRW == null)
                    configRW = new ComboBox2ConfigReaderWriter(this);
                return configRW;
            }
        }
    }

    public class ComboBox2DataSource : IList
    {
        private class DataSourceItem
        {
            private string keyval;

            public string Key { get { return keyval; } }
            public string Val { get { return keyval; } }

            public DataSourceItem(object val)
            {
                this.keyval = val.ToString();
            }

            public override string ToString()
            {
                return Val;
            }
        }

        private List<DataSourceItem> rawList = new List<DataSourceItem>();
        private ComboBox2 parent = null;

        public ComboBox2DataSource(ComboBox2 parent)
        {
            this.parent = parent;
            RefreshDataSource();
        }

        /// <summary>
        /// ForTest
        /// </summary>
        public ComboBox2DataSource()
        {
        }

        private int SearchSameValue(string val)
        {
            for (int i = 0; i < rawList.Count; i++)
            {
                if (rawList[i].Val == val)
                    return i;
            }
            return -1;
        }

        public int Add(object value)
        {
            var dsItem = new DataSourceItem(value);
            var idxInList = SearchSameValue(dsItem.Val);
            if (idxInList >= 0)
                rawList.RemoveAt(idxInList);
            rawList.Insert(0, dsItem);
            RefreshDataSource();

            return 0;
        }

        private void RefreshDataSource()
        {
            if (parent != null && Count > 0)
            {
                parent.DataSource = null;
                parent.DataSource = this;
                parent.DisplayMember = "Key";
                parent.ValueMember = "Val";
            }
        }

        public void Clear()
        {
            rawList.Clear();
        }

        public bool Contains(object value)
        {
            var dsItem = new DataSourceItem(value);
            return rawList.Contains(dsItem);
        }

        public int IndexOf(object value)
        {
            var dsItem = new DataSourceItem(value);
            return rawList.IndexOf(dsItem);
        }

        public void Insert(int index, object value)
        {
            //indexは無視する
            this.Add(value);
        }

        public bool IsFixedSize
        {
            get { return false; }
        }

        public bool IsReadOnly
        {
            get { return false; }
        }

        public void Remove(object value)
        {
            var dsItem = new DataSourceItem(value);
            rawList.Remove(dsItem);
        }

        public void RemoveAt(int index)
        {
            rawList.RemoveAt(index);
        }

        public object this[int index]
        {
            get
            {
                return rawList[index];
            }
            set
            {
                rawList[index] = new DataSourceItem(value);
            }
        }

        public void CopyTo(Array array, int index)
        {
            rawList.CopyTo((DataSourceItem[])array, index);
        }

        public int Count
        {
            get { return rawList.Count; }
        }

        public bool IsSynchronized
        {
            get { return false; }
        }

        private object syncRoot = new object();
        public object SyncRoot
        {
            get { return syncRoot; }
        }

        public System.Collections.IEnumerator GetEnumerator()
        {
            return rawList.GetEnumerator();
        }
    }

    public class ComboBox2ConfigReaderWriter : IConfigReaderWriter
    {
        //Spec: ファイルフォーマット
        //
        //独自形式の設定ファイルとする
        //1行1コントロール設定とする。
        //フォーマットは下記の通り。
        //
        //＜コントロールName＞\t＜最新フォルダパス＞,＜フォルダパス＞,,,,,＜最古フォルダパス＞\r\n
        //
        //※フォルダパス部には検索条件が来る場合も考慮する必要あり。
        //

        private ComboBox2 parent;

        private IList DataSource { get; set; }
        private string Id { get; set; }

        public ComboBox2ConfigReaderWriter(ComboBox2 parent)
        {
            this.parent = parent;
            this.DataSource = parent.DataSource;
            this.Id = parent.Id;
        }

        /// <summary>
        /// ForTest
        /// </summary>
        /// <param name="datasource"></param>
        /// <param name="id"></param>
        internal ComboBox2ConfigReaderWriter(IList datasource, string id)
        {
            this.parent = null;
            this.DataSource = datasource;
            this.Id = id;
        }

        public void Read(Stream stream)
        {
            StreamReader sr = new StreamReader(stream);
            var lineStr = "";

            while ((lineStr = sr.ReadLine()) != null)
            {
                if (!lineStr.StartsWith(Id))
                    continue;
                ReadHistory(lineStr.Replace(Id + "\t", ""));
                break;
            }
        }

        private void ReadHistory(string historys)
        {
            var array = historys.Split(',');
            for (int i = 0; i < array.Length; i++)
                DataSource.Add(array[i]);
        }

        public void Write(Stream stream)
        {
            //Spec:パラメーターのストリームの末尾へ追加書き込みする。
            //ControlConfiigurationクラスが、保存時に毎回設定ファイルを作り直すということを行なっている。

            var historyData = MakeHistoryDataForWrite();
            if (historyData == null)
                return;
            stream.Seek(0, SeekOrigin.End);
            var bytes = Encoding.UTF8.GetBytes(historyData);
            stream.Write(bytes, 0, bytes.Length);
        }

        private string MakeHistoryDataForWrite()
        {
            if (DataSource.Count == 0)
                return null;

            StringBuilder sb = new StringBuilder();
            sb.Append(Id + "\t");
            for (var i = DataSource.Count - 1; i >= 0; i--)
                sb.Append(DataSource[i] + (i != 0 ? "," : "\r\n"));
            return sb.ToString();
        }
    }
}
